/**
 * 
 * @author Jan
 *
 */
public class IO implements Constants {

	/** The queue of processes waiting for free memory */
	private Queue ioQueue;
	/** A reference to the statistics collector */
	private Statistics statistics;
	/** The amount of memory in the memory device */
	private long averageIoTime;
	/** The amount of free memory in the memory device */
	private long ioFrequency;
	private Process ioProcess;
	
	public IO(Queue ioQueue, long averageIoTime, Statistics statistics, Gui gui) {
		this.ioQueue = ioQueue;
		this.statistics = statistics;
		this.averageIoTime = averageIoTime;
		this.ioProcess = null;
		this.ioFrequency = averageIoTime/3; //an interrupt is called on the CPU 3 times as often as the processing time of the IO
	}
	
	/**
	 * Adds a process to the CPU queue.
	 * @param p	The process to be added.
	 */
	public void insertProcess(Process p) {
		ioQueue.insert(p);
		p.setNofTimesInIoQueue(p.getNofTimesInIoQueue()+1);
	}
	
	/**
	 * Places next process from IO-Queue into
	 * processing unit
	 */
	public Process getNextProcess(){
		if (!ioQueue.isEmpty()){
			ioProcess = (Process) ioQueue.removeNext();
			return ioProcess;
		}
		
		return null; //If empty

	}
	
	/**
	 * Calculates the time used by Input/Output on
	 * the active Process
	 * @return Returns result of processing calculation
	 */
	public int doProcessing(){
		
		if(ioProcess != null){
			ioProcess.setTimeSpentInIo(ioProcess.getAvgIoInterval());
			return END_IO;
		}
		return -1;
		
	}
	
	public long getIoDelay(){
		return averageIoTime;
	}

	public void endActiveProcess(){
		this.ioProcess = null;
	}
	
	public int getNofTimesInIOQueue() {
		return statistics.nofTimesInIOQueue;
	}

	public void setNofTimesInIOQueue() {
		statistics.nofTimesInIOQueue++;
	}
	
	/**
	 * This method is called when a discrete amount of time has passed.
	 * @param timePassed	The amount of time that has passed since the last call to this method.
	 */
	public void timePassed(long timePassed) {
		statistics.ioQueueLengthTime += ioQueue.getQueueLength()*timePassed;
		if (ioQueue.getQueueLength() > statistics.ioQueueLargestLength) {
			statistics.ioQueueLargestLength = ioQueue.getQueueLength(); 
		}
    }
    
    public Process getProcess(){
		return ioProcess;
	}
	
	public long getIoFrequency(){
		return ioFrequency;
	}
	
}
